import asyncio
import json
import os
import sys
import time
import uuid
from datetime import datetime

import tornado.httpclient

pro_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
sys.path.append(pro_path)
from common.log import logger
from common import constants
from bot.insurance_planner_gpt.utils.conversation_cache import put_conversation, get_conversation
# from bot.insurance_planner_gpt.utils.conversation_cache import put_session_id_msg, get_session_id_msg
from bot.insurance_planner_gpt.context_local_util import context_data
from bot.insurance_planner_gpt.tele_wechat_assistant import TeleWechatAssistant
from bot.insurance_planner_gpt.config.conf import profile_
from bot.insurance_planner_gpt.agent.script.add_wechat import AddWechat
from bot.insurance_planner_gpt.db.redis.hz_dialogue_storage import HzDialogueStorage
from bot.insurance_planner_gpt.hz.hz_date_transmission import user_ask_hangup, set_add_wechat
from bot.insurance_planner_gpt.hz.hz_date_transmission import delete_data

pro_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
sys.path.append(pro_path)

add_wechat = AddWechat()
hzDialogueStorage = HzDialogueStorage()

try:
    loop = asyncio.get_event_loop()
except RuntimeError:
    asyncio.set_event_loop(asyncio.new_event_loop())
    loop = asyncio.get_event_loop()


class StatusHandler(tornado.web.RequestHandler):

    async def get(self):
        pass


async def async_generator(chat_reply):
    for char in chat_reply:
        yield char
        await asyncio.sleep(0.005)


class InitHandler(tornado.web.RequestHandler):

    async def get(self):
        date_time = int(time.time() * 1000)
        request_time_msg = time.time()
        request_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        sessionId = self.get_argument('sessionId', '')
        workSpaceId = self.get_argument('workSpaceId', '')
        message_id = str(uuid.uuid4()).replace('-', '')
        loop.run_in_executor(None, grab_wechat_code, sessionId)
        context_data.set({"session_id": sessionId, "message_id": message_id})
        finally_content = ""
        conversation_history = []
        start_time = time.time()
        logger.info(
            '[InitHandler] LLM_Time 执行时间:{} sessionId:{} time:{} 从开始到现在时间:{}'
            .format(date_time, sessionId, (time.time() - start_time) * 1000, (time.time() - request_time_msg) * 1000))
        try:
            chat_reply = '喂，您好。诶，你好，不好意思打扰您了，我是慧择保险网的。我们想提升您的咨询体验，现在给您服务升级为专属1对1的服务顾问，关于保险的任何问题都可以找我聊，那我这边用官方企业微信添加您，辛苦您那边操作同意一下好吧？'
            async for char in async_generator(chat_reply):
                self.write(char)
                await self.flush()
                finally_content += char
        finally:
            logger.info(
                '[InitHandler] 执行时间:{} sessionId:{} 输出流结束耗时:{} 大模型返回文本:{}'
                .format(date_time, sessionId, (time.time() - start_time) * 1000, finally_content))
            if finally_content:
                conversation_history = put_conversation(finally_content, constants.ROLE_ASSISTANT, sessionId,
                                                        request_time)
            await user_ask_hangup(sessionId, '否', date_time)
            logger.info(
                '[InitHandler] 执行时间:{} sessionId:{} history:{} 整体耗费时间:{}'
                .format(date_time, sessionId, conversation_history, (time.time() - request_time_msg) * 1000))


def grab_wechat_code(sessionId):
    logger.info('[grab_wechat_code] 抓取用户信息 sessionId:{}'.format(sessionId))
    if '-2242-' in sessionId:
        customer_id = asyncio.run(add_wechat.get_case_info(sessionId))
        if customer_id:
            # put_session_id_msg(sessionId, customer_id)
            asyncio.run(add_wechat.grab_wechat_code(customer_id, sessionId))


class CacheUserMessageHandler(tornado.web.RequestHandler):

    async def get(self):
        request_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        message = self.get_argument('message', '')
        sessionId = self.get_argument('sessionId', '')
        logger.info(
            '[CacheUserMessageHandler]AI broadcast user suddenly speaks sessionId :{} message:{}'
            .format(sessionId, message))
        conversation_history = put_conversation(message, constants.ROLE_USER, sessionId, request_time)
        logger.info(
            '[CacheUserMessageHandler] AI broadcast user suddenly speaks 历史对话数据 sessionId :{} history:{}'
            .format(sessionId, conversation_history))


class RetryAddWechatHandler(tornado.web.RequestHandler):

    async def get(self):
        resp_json = {}
        date_time = int(time.time() * 1000)
        sessionId = self.get_argument('sessionId', '')
        if sessionId and '-2242-' in sessionId:
            loop.run_in_executor(None, grab_wechat_code, sessionId)
            await asyncio.sleep(10)
            result = await add_wechat.launch_add_wechat(sessionId)
            logger.info('[RetryAddWechatHandler] 重新发起加微请求  执行时间:{} sessionId:{} 返回结果:{}'
                        .format(date_time, sessionId, result))
            resp_json['data'] = result
        else:
            resp_json['data'] = 'sessionId为空 或者sessionId 不是慧择空间'
        self.write(json.dumps(resp_json, ensure_ascii=False))


class CheckHangoutHandler(tornado.web.RequestHandler):

    async def get(self):
        result = False
        sessionId = self.get_argument('sessionId', '')
        resp_json = {}
        try:
            hang_up_result = await hzDialogueStorage.get_tele_wechat_skill_hangup(sessionId)
            if hang_up_result and '是' in hang_up_result:
                result = True
        except Exception:
            logger.info('获取挂机表示报错 sessionId:{}'.format(sessionId))
        finally:
            resp_json['data'] = result
            resp_json['code'] = 200
            logger.info('[CheckHangoutHandler] 是否挂断 sessionId :{} 返回结果:{}'.format(sessionId, result))
            self.write(json.dumps(resp_json, ensure_ascii=False))


async def is_add_wechat(wechat_skill, sessionId, date_time):
    if '服务通知' == wechat_skill and '-2242-' in sessionId:
        add_wechat_one = await hzDialogueStorage.get_is_add_wechat(sessionId)
        if '是' != add_wechat_one:
            result = await add_wechat.launch_add_wechat(sessionId)
            logger.info('[StreamHandler] 发起加微请求  执行时间:{} sessionId:{} 返回结果:{}'
                        .format(date_time, sessionId, result))
            await set_add_wechat(sessionId, '是', date_time)
            # customer_id = get_session_id_msg(sessionId)
            # if customer_id:
            #     await add_wechat.launch_send_msg_wechat(sessionId, customer_id)
            #     logger.info('[StreamHandler] 发送加微短信  执行时间:{} sessionId:{} customer_id :{} 返回结果:{}'
            #                 .format(date_time, sessionId, customer_id, result))


class StreamHandler(tornado.web.RequestHandler):

    async def get(self):
        date_time = int(time.time() * 1000)
        request_time_msg = time.time()
        request_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        message = self.get_argument('message', '')
        sessionId = self.get_argument('sessionId', '')
        workSpaceId = self.get_argument('workSpaceId', '')
        logger.info('[StreamHandler] user ask 执行时间:{} sessionId:{} msg:{}'.format(date_time, sessionId, message))
        base_info = {}
        new_message = message
        conversation_history = put_conversation(new_message, constants.ROLE_USER, sessionId, request_time)
        message_id = str(uuid.uuid4()).replace('-', '')
        context_data.set({"session_id": sessionId, "message_id": message_id})
        last_offset = 0
        finally_content = ''
        wechat_assistant = TeleWechatAssistant()
        logger.info('[StreamHandler] llm conversation 执行时间:{} sessionId :{} history:{} 执行耗时:{}'
                    .format(date_time, sessionId, conversation_history, (time.time() - request_time_msg) * 1000))
        start_time = time.time()
        chat_reply = await wechat_assistant.async_reply(conversation_history, sessionId, base_info=base_info,
                                                        is_stream=True, date_time=date_time)
        llm_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        wechat_skill = wechat_assistant.wechat_skill
        user_question = wechat_assistant.user_question
        asyncio.ensure_future(is_add_wechat(wechat_skill, sessionId, date_time))
        logger.info(
            '[StreamHandler] LLM_Time 执行时间:{} sessionId:{} time:{} 从开始到现在时间:{}'
            .format(date_time, sessionId, (time.time() - start_time) * 1000, (time.time() - request_time_msg) * 1000))
        try:
            async for data in chat_reply:
                # chunk_data = data['choices'][0]["delta"]["content"]
                token_offset = len(data["text"])
                chunk_data = data["text"][last_offset:]
                last_offset = token_offset
                chunk_data = chunk_data.replace("�", "")
                self.write(chunk_data)
                await self.flush()
                if last_offset == 1:
                    logger.info(
                        '[StreamHandler] 执行时间:{} sessionId:{} 第一次推送流耗时:{}'
                        .format(date_time, sessionId, (time.time() - start_time) * 1000))
                finally_content += chunk_data
        finally:
            logger.info(
                '[StreamHandler] 执行时间:{} sessionId:{} 输出流结束耗时:{} 大模型返回文本:{}'
                .format(date_time, sessionId, (time.time() - start_time) * 1000, finally_content))
            if finally_content:
                conversation_history = put_conversation(finally_content, 'assistant', sessionId, llm_time,
                                                        user_question=user_question, sales_skill_name=wechat_skill)

            data = '否'
            if '再见' in finally_content or '拜拜' in finally_content:
                data = '是'
            await user_ask_hangup(sessionId, data, date_time)
            # 流式输出的结果保存
            logger.info(
                '[StreamHandler] 执行时间:{} sessionId:{} history:{} 整体耗费时间:{}'
                .format(date_time, sessionId, conversation_history, (time.time() - request_time_msg) * 1000))


class HangupHandler(tornado.web.RequestHandler):

    async def get(self):
        sessionId = self.get_argument('sessionId', '')
        await delete_data(sessionId)
        conversation_history = get_conversation(sessionId)
        logger.info(
            '[HangupHandler] Hang up the phone sessionId:{} history:{}'.format(sessionId, conversation_history))


if __name__ == '__main__':
    _routes = [
        (r"/add_wework/status", StatusHandler),
        (r"/add_wework/init", InitHandler),
        (r"/add_wework/stream_message", StreamHandler),
        (r"/add_wework/check_hangout_action", CheckHangoutHandler),
        (r"/add_wework/cache_user_message", CacheUserMessageHandler),
        (r"/add_wework/hangup", HangupHandler),
        (r"/add_wework/retry_add_wechat", RetryAddWechatHandler),
    ]
    app = tornado.web.Application(handlers=_routes, debug=False)
    http_server = tornado.httpserver.HTTPServer(app)
    port = profile_['add_wechat_server']['port']  # 8082
    http_server.bind(port)
    logger.info(f"********** add_wechat server started on port:{port} **********")
    process_num = profile_['add_wechat_server']['process_num']
    http_server.start(process_num)
    # 项目启动时进行初始化一次
    tornado.ioloop.IOLoop.current().start()
